package com.huilian.tool.douyin.web.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huilian.tool.common.config.DouYinConfig;
import com.huilian.tool.douyin.enums.DouYinEventTypeEnum;
import com.huilian.tool.common.utils.HuiLianHttpUtil;
import com.huilian.tool.douyin.enums.ScopeEnum;
import com.huilian.tool.douyin.web.service.CommonService;
import com.huilian.tool.douyin.web.service.DefaultDouYinMsgEventService;
import com.huilian.tool.douyin.web.service.DouYinService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 少凡
 * date 2022/5/27 11:58
 * version 1.0
 */


@Service
@Slf4j
public class DouYinServiceImpl implements DouYinService {

    @Resource
    private DouYinConfig douYinConfig;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private CommonService commonService;
    @Resource
    private DefaultDouYinMsgEventService defaultDouYinMsgEventService;

    /**
     * 拼接获取抖音授权码请求URL
     *
     * @param redirectUri
     * @param state
     * @return
     */
    @Override
    public String getOauthCode(String redirectUri, String state) {

        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/platform/oauth/connect/");

        StringBuilder scopeList = new StringBuilder();

        for (ScopeEnum scope : ScopeEnum.values()) {
            scopeList.append(scope.getCode()).append(",");
        }

        scopeList.deleteCharAt(scopeList.lastIndexOf(","));

        System.out.println("scope:" + scopeList);

        Map<String, Object> params = new HashMap<>();
        params.put("client_key", douYinConfig.getClientKey());
        params.put("response_type", "code");
        params.put("scope", scopeList.toString());
        params.put("redirect_uri", redirectUri);
        params.put("state", state);

        return HuiLianHttpUtil.buildUrl(url.toString(), params);
    }

    /**
     * 为用户授权第三方接口调用的凭证，存储在客户端，可能会被窃取，泄漏后可能会发生用户隐私数据泄漏的风险，建议存储在服务端。
     *
     * @param code
     * @return
     */
    @Override
    public JSONObject getAccessToken(String code) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/oauth/access_token/");

        Map<String, Object> params = new HashMap<>();
        params.put("client_key", douYinConfig.getClientKey());
        params.put("client_secret", douYinConfig.getClientSecret());
        params.put("grant_type", "authorization_code");
        params.put("code", code);
        String result = restTemplate.postForObject(url.toString(), params, String.class);
        return commonService.unifiedReturn(result);

    }

    /**
     * 通过旧的refresh_token获取新的refresh_token，调用后旧refresh_token会失效，
     * 新refresh_token有30天有效期。最多只能获取5次新的refresh_token，5次过后需要用户重新授权。
     *
     * @param refreshToken
     * @return
     */
    @Override
    public JSONObject refreshToken(String refreshToken) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/oauth/renew_refresh_token/");
        Map<String, Object> params = new HashMap<>();
        params.put("client_key", douYinConfig.getClientKey());
        params.put("refresh_token", refreshToken);
        String result = restTemplate.postForObject(url.toString(), params, String.class);
        return commonService.unifiedReturn(result);
    }

    /**
     * 刷新access_token或续期不会改变refresh_token的有效期；如果需要刷新refresh_token有效期可以调用/oauth/renew_refresh_token/接口
     * 当access_token过期（过期时间15天）后，可以通过该接口使用refresh_token（过期时间30天）进行刷新：
     *
     * @param refreshToken
     * @return
     */
    @Override
    public JSONObject refreshAccessToken(String refreshToken) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/oauth/refresh_token/");
        Map<String, Object> params = new HashMap<>();
        params.put("client_key", douYinConfig.getClientKey());
        params.put("grant_type", "refresh_token");
        params.put("refresh_token", refreshToken);
        String result = restTemplate.postForObject(url.toString(), params, String.class);
        return commonService.unifiedReturn(result);
    }

    @Override
    public String getSilenceCode(String redirectUri, String state) {
        String url = new StringBuilder(douYinConfig.getUrl()).append("/oauth/authorize/v2/").toString();
        Map<String, Object> params = new HashMap<>();
        params.put("client_key", douYinConfig.getClientKey());
        params.put("response_type", "code");
        params.put("scope", "login_id");
        params.put("redirect_uri", redirectUri);
        params.put("state", state);
        return HuiLianHttpUtil.buildUrl(url, params);
    }

    /**
     * 该接口获取用户的抖音公开信息，包含昵称、头像、性别和地区；适用于抖音
     * Scope: user_info 需要用户授权
     *
     * @param openId
     * @param accessToken
     * @return
     */
    @Override
    public JSONObject getUserInfo(String openId, String accessToken) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/oauth/userinfo/");
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("open_id", openId);

        return commonService.unifiedReturn(restTemplate.postForObject(url.toString(), params, String.class));
    }


    /**
     * 获取用户最近的粉丝列表，不保证顺序；目前可查询的粉丝数上限5千。该接口适用于抖音
     * Scope: fans.list 需要用户授权
     *
     * @param openId
     * @param accessToken
     * @param count
     * @param cursor
     * @return
     */
    @Override
    public JSONObject getFansList(String openId, String accessToken, Integer count, Integer cursor) {

        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/fans/list/");

        Map<String, Object> params = new HashMap<>();
        params.put("open_id", openId);
        params.put("cursor", cursor);
        params.put("count", count);

        String reqUrl = HuiLianHttpUtil.buildUrl(url.toString(), params);

        return commonService.getRequest(reqUrl, accessToken);

    }

    /**
     * Scope: following.list 需要用户授权
     * 获取用户的关注列表；该接口适用于抖音。
     *
     * @param openId
     * @param count
     * @param cursor
     * @return
     */
    @Override
    public JSONObject getFollowingList(String openId, String accessToken, Integer count, Integer cursor) {

        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/following/list/");

        Map<String, Object> params = new HashMap<>();
        params.put("open_id", openId);
        params.put("count", count);
        params.put("cursor", cursor);
        String reqUrl = HuiLianHttpUtil.buildUrl(url.toString(), params);
        return commonService.getRequest(reqUrl, accessToken);
    }

    @Override
    public JSONObject fansCheck(String followerOpenId, String openId, String accessToken) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/fans/check/");

        Map<String, Object> params = new HashMap<>();
        params.put("follower_open_id", followerOpenId);
        params.put("open_id", openId);
        String reqUrl = HuiLianHttpUtil.buildUrl(url.toString(), params);
        return commonService.getRequest(reqUrl, accessToken);
    }

    @Override
    public JSONObject getVideoList(String openId, String accessToken, Integer count, Integer cursor) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/video/list/");

        Map<String, Object> params = new HashMap<>();
        params.put("open_id", openId);
        params.put("count", count);
        params.put("cursor", cursor);
        String reqUrl = HuiLianHttpUtil.buildUrl(url.toString(), params);
        return commonService.getRequest(reqUrl, accessToken);
    }

    /**
     * * Scope: video.data 需要用户授权 需要申请权限
     * 该接口 用于查询用户特定视频的数据, 如点赞数, 播放数等，返回的数据是实时的。该接口适用于抖音。
     *
     * @param openId
     * @param accessToken
     * @param itemIds
     * @return
     */
    @Override
    public JSONObject getVideoData(String openId, String accessToken, String[] itemIds) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/video/data/?open_id=").append(openId);
        Map<String, Object> params = new HashMap<>();
        params.put("item_ids", itemIds);
        return commonService.PostRequest(url.toString(), accessToken, params);

    }

    /**
     * 评论列表
     * Scope: item.comment 需要申请权限
     * 需要用户授权 该接口用于获取评论列表。
     *
     * @param openId
     * @param accessToken
     * @param count
     * @param cursor
     * @return
     */
    @Override
    public JSONObject getCommentList(String openId, String accessToken, String itemId, Integer count, Integer cursor) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/item/comment/list/");

        Map<String, Object> params = new HashMap<>();
        params.put("open_id", openId);
        params.put("item_id", itemId);
        params.put("count", count);
        params.put("cursor", cursor);
        params.put("sort_type", "time");
        String reqUrl = HuiLianHttpUtil.buildUrl(url.toString(), params);


        return commonService.getRequest(reqUrl, accessToken);
    }

    /**
     * 评论回复列表
     * Scope: item.comment 需要申请权限 需要用户授权
     * 该接口用于获取评论回复列表。
     *
     * @param openId
     * @param accessToken
     * @param itemId
     * @param commentId
     * @param count
     * @param cursor
     * @return
     */
    @Override
    public JSONObject getCommentReplyList(String openId, String accessToken, String itemId, String commentId, Integer count, Integer cursor) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/item/comment/reply/list/");

        Map<String, Object> params = new HashMap<>();
        params.put("open_id", openId);
        params.put("item_id", itemId);
        params.put("comment_id", commentId);
        params.put("count", count);
        params.put("cursor", cursor);
        params.put("sort_type", "time");
        String reqUrl = HuiLianHttpUtil.buildUrl(url.toString(), params);
        return commonService.getRequest(reqUrl, accessToken);
    }

    /**
     * 回复视频评论
     * Scope: item.comment 需要申请权限 需要用户授权
     * 该接口用于回复视频评论。只能回复授权用户自己发布的视频。
     *
     * @param openId
     * @param accessToken
     * @param itemId
     * @param commentId
     * @param content
     * @return
     */
    @Override
    public JSONObject commentReply(String openId, String accessToken, String itemId, String content, String commentId) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/item/comment/reply/?open_id=").append(openId);
        Map<String, Object> params = new HashMap<>();
        params.put("item_id", itemId);
        params.put("comment_id", commentId);
        params.put("content", content);
        return commonService.PostRequest(url.toString(), accessToken, params);
    }

    /**
     * 直接对视频进行评论
     * Scope: item.comment 需要申请权限 需要用户授权
     * 该接口用于回复视频评论。只能回复授权用户自己发布的视频。
     *
     * @param openId
     * @param accessToken
     * @param itemId
     * @param content
     * @return
     */
    @Override
    public JSONObject commentReply(String openId, String accessToken, String itemId, String content) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/item/comment/reply/?open_id=").append(openId);
        Map<String, Object> params = new HashMap<>();
        params.put("item_id", itemId);
        params.put("content", content);
        return commonService.PostRequest(url.toString(), accessToken, params);
    }

    @Override
    public JSONObject getShopPoiQuery(String accessToken, Integer page, Integer size) {
        StringBuilder url = new StringBuilder(douYinConfig.getUrl()).append("/goodlife/v1/shop/poi/query/");
        Map<String, Object> params = new HashMap<>();
        params.put("size", size);
        params.put("page", page);
        String reqUrl = HuiLianHttpUtil.buildUrl(url.toString(), params);
        System.out.println("reqUrl: " + reqUrl);
        return commonService.getRequest("https://open.douyin.com/goodlife/v1/shop/poi/query/?page=1&size=20", accessToken);
    }

    /**
     * 抖音回调
     */
    @Override
    public String receiveDouYinNotice(HttpServletRequest request) {
        try{
            log.info("抖音回调");
            // 抖音侧收到成功请求时也可能会继续重复推送
            String MsgId = request.getHeader("Msg-Id");
            log.info("抖音Msg-Id: {}",MsgId);
            String str, wholeStr = "";
            BufferedReader br = request.getReader();
            while((str = br.readLine()) != null){
                wholeStr += str;
            }
            log.info("抖音回调报文: {}",wholeStr);
            JSONObject body = JSON.parseObject(wholeStr);
            log.info("抖音回调消息类型: {}",body.getString("event"));
            if(DouYinEventTypeEnum.VERIFY_WEBHOOK.getCode().equals(body.getString("event"))){
                // 回调验证
                log.info("抖音回调验证verify_webhook");
                // {"event":"verify_webhook","client_key":"aw53u6j3arw62ssa","from_user_id":"","content":{"challenge":88431307},"log_id":"021690524961394d427b8f1f4597b67348a982efac15db231e674","event_id":""}        log.info("订单支付回调通知报文{}", response);
                // 注意回调给抖音{"challenge":88431307}参数
                log.info("content: {}",body.getString("content"));
                return body.getString("content");
            }

            // 商品审核结果同步
            // 获取请求头中的加签信息
            String signature = request.getHeader("X-Douyin-Signature");
            log.info("抖音,获取请求头中的加签信息: {}",signature);
            log.info("抖音appSecret: {}",douYinConfig.getIotboxLifeSecret());
            String data = douYinConfig.getIotboxLifeSecret() + wholeStr;
            String sign = DigestUtils.sha1Hex(data);
            log.info("抖音sign: {}",sign);
            if(!sign.equals(signature)){
                log.error("抖音回调验签失败");
                return "验签失败";
            }
            if (DouYinEventTypeEnum.LIFE_PRODUCT_COMMON_AUDIT.getCode().equals(body.getString("event"))){
                // 商品审核结果同步事件
                return defaultDouYinMsgEventService.lifeProductCommonAuditEventService(body);
            } else if (DouYinEventTypeEnum.LIFE_TRADE_ORDER_NOTIFY.getCode().equals(body.getString("event"))){
                // 订单消息通知,用户支付成功
                return defaultDouYinMsgEventService.lifeTradeOrderNotifyEventService(body);
            } else if (DouYinEventTypeEnum.LIFE_TRADE_CERTIFICATE_NOTIFY.getCode().equals(body.getString("event"))){
                // 券消息通知, 核销、撤销核销、退款成功等通知
                return defaultDouYinMsgEventService.lifeTradeCertificateNotifyEventService(body);
            } else {
                log.error("未知消息类型: UNKNOWN_MESSAGE_EVENT");
                return "UNKNOWN_MESSAGE_EVENT";
            }
        } catch (Exception e){
            e.printStackTrace();
            log.warn("获取请求内容失败，{}", e.getMessage());
            return "FAIL";
        }
    }


}
